package com.gitee.wsl.mathematics.complex.quaternion.ext


import com.gitee.wsl.mathematics.complex.quaternion.Quat


infix fun Quat.pow(pow: Number): Quat {
    if (pow is Int) return power(this, pow)
    if (floor(pow.toDouble()) == pow.toDouble()) return power(this, pow.toInt())
    return ( ln() * pow ).exp()
}

private fun power(x: Quat, a: Int): Quat = when {
    a < 0 -> -(power(x, -a))
    a == 0 -> Quat.ONE
    a == 1 -> x
    a == 2 -> pwr2(x)
    a == 3 -> pwr3(x)
    a == 4 -> pwr4(x)

    else -> {
        val x4 = pwr4(x)
        var y = x4
        repeat((1 until a / 4).count()) { y *= x4 }
        if (a % 4 == 3) y *= pwr3(x)
        if (a % 4 == 2) y *= pwr2(x)
        if (a % 4 == 1) y *= x
        y
    }
}

private fun pwr2(x: Quat): Quat {
    val aa = 2 * x.w
    return Quat(x.w * x.w - (x.x * x.x + x.y * x.y + x.z * x.z), aa * x.x, aa * x.y, aa * x.z)
}

private fun pwr3(x: Quat): Quat {
    val a2 = x.w * x.w
    val n1 = x.x * x.x + x.y * x.y + x.z * x.z
    val n2 = 3.0 * a2 - n1
    return Quat(x.w * (a2 - 3 * n1), x.x * n2, x.y * n2, x.z * n2)
}

private fun pwr4(x: Quat): Quat {
    val a2 = x.w * x.w
    val n1 = x.x * x.x + x.y * x.y + x.z * x.z
    val n2 = 4 * x.w * (a2 - n1)
    return Quat(a2 * a2 - 6 * a2 * n1 + n1 * n1, x.x * n2, x.y * n2, x.z * n2)
}